package oglutil

import (
	"math"

	"github.com/go-gl/mathgl/mgl32"
)

//Direction 摄像头移动方向
type Direction int

//前后左右
const (
	FORWARD Direction = iota
	BACKWARD
	LEFT
	RIGHT
)

//Camera 欧拉角摄像机 注意万向节死锁
type Camera struct {
	Position mgl32.Vec3
	Front    mgl32.Vec3
	Up       mgl32.Vec3
	zoom     float32
	first    bool
	lastX    float32
	lastY    float32
	yaw      float32
	pitch    float32
}

//NewCamera 返回1个Camera 位置 方向(-direction) 上
func NewCamera(pos, front, up mgl32.Vec3) *Camera {
	return &Camera{
		Position: pos,
		Front:    front,
		Up:       up,
		zoom:     45,
		first:    true,
		yaw:      -90,
		pitch:    0,
	}
}

//View 返回视图矩阵
func (ca *Camera) View() mgl32.Mat4 {
	return mgl32.LookAtV(ca.Position, ca.Position.Add(ca.Front), ca.Up)
}

//Move 前后左右移动
func (ca *Camera) Move(dir Direction, speed float32) {
	if dir == FORWARD {
		ca.Position = ca.Position.Add(ca.Front.Mul(speed))
	} else if dir == BACKWARD {
		ca.Position = ca.Position.Sub(ca.Front.Mul(speed))
	} else if dir == LEFT {
		ca.Position = ca.Position.Sub(ca.Front.Cross(ca.Up).Normalize().Mul(speed))
	} else if dir == RIGHT {
		ca.Position = ca.Position.Add(ca.Front.Cross(ca.Up).Normalize().Mul(speed))
	}
}

//Turn 转动
func (ca *Camera) Turn(xpos, ypos float32) {
	if ca.first {
		ca.lastX = xpos
		ca.lastY = ypos
		ca.first = false
	}
	xoffset := xpos - ca.lastX
	yoffset := ca.lastY - ypos
	ca.lastX = xpos
	ca.lastY = ypos
	var sensitivity float32 = 0.05
	xoffset = xoffset * sensitivity
	yoffset = yoffset * sensitivity
	ca.yaw = ca.yaw + float32(xoffset)
	ca.pitch = ca.pitch + float32(yoffset)
	if ca.pitch > 89.0 {
		ca.pitch = 89.0
	}
	if ca.pitch < -89.0 {
		ca.pitch = -89.0
	}
	ca.Front = mgl32.Vec3{
		float32(math.Cos(float64(mgl32.DegToRad(ca.pitch))) * math.Cos(float64(mgl32.DegToRad(ca.yaw)))),
		float32(math.Sin(float64(mgl32.DegToRad(ca.pitch)))),
		float32(math.Cos(float64(mgl32.DegToRad(ca.pitch))) * math.Sin(float64(mgl32.DegToRad(ca.yaw)))),
	}
	ca.Front = ca.Front.Normalize()
}

//Zoom  影响投影矩阵 裁剪空间
func (ca *Camera) Zoom(yoff float32) {
	if ca.zoom >= 1.0 && ca.zoom <= 45.0 {
		ca.zoom -= yoff
	}
	if ca.zoom <= 1.0 {
		ca.zoom = 1.0
	}
	if ca.zoom >= 45.0 {
		ca.zoom = 45.0
	}
}

//Projection 获取投影矩阵
func (ca *Camera) Projection(aspect, near, far float32) mgl32.Mat4 {
	return mgl32.Perspective(mgl32.DegToRad(ca.zoom), aspect, near, far)
}
